/*
 * $RCSfile: ChangeColumn.java,v $
 * $Revision: 1.1 $
 * $Date: 2014-03-01 $
 *
 * Copyright (C) 2005 Skin, Inc. All rights reserved.
 *
 * This software is the proprietary information of Skin, Inc.
 * Use is subject to license terms.
 */
package com.skin.webcat.database;

import com.skin.webcat.database.mysql.MySql;
import com.skin.webcat.util.Sql;

/**
 * <p>Title: ChangeColumn</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * @author xuesong.net
 * @version 1.0
 */
public class ChangeColumn extends Changeable {
    private ChangeValue columnName;
    private ChangeValue typeName;
    private ChangeValue columnSize;
    private ChangeValue decimalDigits;
    private ChangeValue columnDef;
    private ChangeValue remarks;
    private ChangeValue nullable;
    private ChangeValue autoIncrement;
    private ChangeValue primaryKey;

    /**
     * apply
     */
    @Override
    public void apply() {
        this.columnName.apply();
        this.typeName.apply();
        this.columnSize.apply();
        this.decimalDigits.apply();
        this.columnDef.apply();
        this.remarks.apply();
        this.nullable.apply();
        this.autoIncrement.apply();
        this.primaryKey.apply();
    }

    /**
     * @return the columnName
     */
    public ChangeValue getColumnName() {
        return this.columnName;
    }

    /**
     * @param columnName the columnName to set
     */
    public void setColumnName(ChangeValue columnName) {
        this.columnName = columnName;
    }

    /**
     * @return the typeName
     */
    public ChangeValue getTypeName() {
        return this.typeName;
    }

    /**
     * @param typeName the typeName to set
     */
    public void setTypeName(ChangeValue typeName) {
        this.typeName = typeName;
    }

    /**
     * @return the columnSize
     */
    public ChangeValue getColumnSize() {
        return this.columnSize;
    }

    /**
     * @param columnSize the columnSize to set
     */
    public void setColumnSize(ChangeValue columnSize) {
        this.columnSize = columnSize;
    }

    /**
     * @return the decimalDigits
     */
    public ChangeValue getDecimalDigits() {
        return this.decimalDigits;
    }

    /**
     * @param decimalDigits the decimalDigits to set
     */
    public void setDecimalDigits(ChangeValue decimalDigits) {
        this.decimalDigits = decimalDigits;
    }

    /**
     * @return the columnDef
     */
    public ChangeValue getColumnDef() {
        return this.columnDef;
    }

    /**
     * @param columnDef the columnDef to set
     */
    public void setColumnDef(ChangeValue columnDef) {
        this.columnDef = columnDef;
    }

    /**
     * @return the remarks
     */
    public ChangeValue getRemarks() {
        return this.remarks;
    }

    /**
     * @param remarks the remarks to set
     */
    public void setRemarks(ChangeValue remarks) {
        this.remarks = remarks;
    }

    /**
     * @return the nullable
     */
    public ChangeValue getNullable() {
        return this.nullable;
    }

    /**
     * @param nullable the nullable to set
     */
    public void setNullable(ChangeValue nullable) {
        this.nullable = nullable;
    }

    /**
     * @return the autoIncrement
     */
    public ChangeValue getAutoIncrement() {
        return this.autoIncrement;
    }

    /**
     * @param autoIncrement the autoIncrement to set
     */
    public void setAutoIncrement(ChangeValue autoIncrement) {
        this.autoIncrement = autoIncrement;
    }

    /**
     * @return the primaryKey
     */
    public ChangeValue getPrimaryKey() {
        return this.primaryKey;
    }

    /**
     * @param primaryKey the primaryKey to set
     */
    public void setPrimaryKey(ChangeValue primaryKey) {
        this.primaryKey = primaryKey;
    }

    /**
     * @return boolean
     */
    @Override
    public boolean modified() {
        /**
         * 如果是自增主键, 忽略nullable和columnDef
         * 不检查主键, 主键变化不依赖于某一个具体的列
         */
        if(this.autoIncrement.getBoolean()) {
            return (this.columnName.modified()
                    || this.typeName.modified()
                    || this.columnSize.modified()
                    || this.decimalDigits.modified()
                    || this.remarks.modified()
                    || this.autoIncrement.modified());
        }
        else {
            return (this.columnName.modified()
                    || this.typeName.modified()
                    || this.columnSize.modified()
                    || this.decimalDigits.modified()
                    || this.columnDef.modified()
                    || this.remarks.modified()
                    || this.nullable.modified()
                    || this.autoIncrement.modified());
        }
    }

    /**
     * @return boolean
     */
    @Override
    public String validate() {
        if(!this.validate(this.columnName)) {
            return "bad column name: [" + this.columnName.getOldValue() + "] - " + "[" + this.columnName.getNewValue() + "]";
        }

        if(!this.validate(this.typeName.getOldValue(), " ")) {
            return "bad data type: [" + this.typeName.getOldValue() + "] - " + "[" + this.typeName.getNewValue() + "]";
        }

        if(!this.validate(this.typeName.getNewValue(), " ")) {
            return "bad data type: [" + this.typeName.getOldValue() + "] - " + "[" + this.typeName.getNewValue() + "]";
        }
        return null;
    }

    /**
     * @param tableName
     * @return String
     */
    @Override
    public String getCreateSql(String tableName) {
        StringBuilder buffer = new StringBuilder();
        buffer.append(MySql.getColumnDefine(this.typeName.getString(), this.columnSize.getInt(), this.decimalDigits.getInt()));

        if(!this.nullable.getBoolean() && !this.autoIncrement.getBoolean()) {
            buffer.append(" not null");
        }

        if(this.columnDef.notEmpty() && !this.autoIncrement.getBoolean()) {
            String defaultValue = this.columnDef.getNewValue();

            if(defaultValue.equalsIgnoreCase("NULL")) {
                buffer.append(" default null");
            }
            else {
                buffer.append(" default '" + Sql.escape(this.columnDef.getString()) + "'");
            }
        }

        if(this.autoIncrement.getBoolean()) {
            buffer.append(" auto_increment");
        }

        if(this.remarks.notEmpty()) {
            buffer.append(" comment '" + Sql.escape(this.remarks.getString()) + "'");
        }
        return buffer.toString();
    }

    /**
     * 该方法将严格的根据列的属性生成列定义语句
     * 不会检查任何的约束, 所以任何情况下都不要修改该方法
     * @param tableName
     * @return String
     */
    @Override
    public String getAlterSql(String tableName) {
        if(!this.modified()) {
            return "";
        }

        StringBuilder buffer = new StringBuilder();
        ChangeValue columnName = this.getColumnName();
        ChangeValue typeName = this.getTypeName();
        ChangeValue columnSize = this.getColumnSize();
        ChangeValue decimalDigits = this.getDecimalDigits();
        ChangeValue nullable = this.getNullable();
        ChangeValue columnDef = this.getColumnDef();
        ChangeValue autoIncrement = this.getAutoIncrement();
        ChangeValue primaryKey = this.getPrimaryKey();
        ChangeValue remarks = this.getRemarks();

        /**
         * 如果新列名未指定则认为删除
         */
        if(columnName.isEmpty()) {
            buffer.append("-- drop column\r\n");
            buffer.append("alter table ");
            buffer.append(tableName);
            buffer.append(" drop ");
            buffer.append(columnName.getOldValue());
            buffer.append(";\r\n");
            return buffer.toString();
        }

        /**
         * 如果旧列名为空则认为新增
         */
        if(columnName.isEmpty(columnName.getOldValue())) {
            buffer.append("-- add column\r\n");
            buffer.append("alter table ");
            buffer.append(tableName);
            buffer.append(" add column " + columnName.getNewValue());
        }
        else {
            if(columnName.modified()) {
                buffer.append("-- change column\r\n");
                buffer.append("alter table ");
                buffer.append(tableName);
                buffer.append(" change " + columnName.getOldValue());
                buffer.append(" ");
                buffer.append(columnName.getNewValue());
            }
            else {
                buffer.append("-- modify column\r\n");
                buffer.append("alter table ");
                buffer.append(tableName);
                buffer.append(" modify " + columnName.getOldValue());
            }
        }

        buffer.append(" ");
        buffer.append(MySql.getColumnDefine(typeName.getString(), columnSize.getInt(), decimalDigits.getInt()));

        if(!nullable.getBoolean() && !autoIncrement.getBoolean()) {
            buffer.append(" not null");
        }

        if(columnDef.notEmpty() && !autoIncrement.getBoolean()) {
            buffer.append(" default '" + Sql.escape(columnDef.getString()) + "'");
        }

        /**
         * 1. 当表无主键时, 此时应该设置 auto_increment primary key
         * 2. 当表无主键并且新增多个主键，并且当前列是自增时, 应该先设置主键，再修改为自增
         */
        if(autoIncrement.getBoolean()) {
            buffer.append(" auto_increment");

            /**
             * 当有且仅有自增键时必须存在主键定义
             * 是否产生主键关键字由外部调用决定
             * 此处只要primaryKey为true就产生主键关键字
             */
            if(primaryKey.getBoolean()) {
                buffer.append(" primary key");
            }
        }

        if(remarks.notEmpty()) {
            buffer.append(" comment '" + Sql.escape(remarks.getString()) + "'");
        }
        buffer.append(";\r\n");
        return buffer.toString();
    }

    /**
     * @return ChangeColumn
     */
    @Override
    public ChangeColumn clone() {
        ChangeColumn changeColumn = new ChangeColumn();
        changeColumn.setColumnName(this.columnName.clone());
        changeColumn.setTypeName(this.typeName.clone());
        changeColumn.setColumnSize(this.columnSize.clone());
        changeColumn.setDecimalDigits(this.decimalDigits.clone());
        changeColumn.setColumnDef(this.columnDef.clone());
        changeColumn.setRemarks(this.remarks.clone());
        changeColumn.setNullable(this.nullable.clone());
        changeColumn.setPrimaryKey(this.primaryKey.clone());
        changeColumn.setAutoIncrement(this.autoIncrement.clone());
        return changeColumn;
    }
}
